<?php
/**
 * @see Epic_Form_Element_Interface
 */
require 'Epic/Form/Element/Interface.php';

/**
 * @see Epic_Form_Element_Abstract
 */
require 'Epic/Form/Element/Abstract.php';

/**
 * @see Epic_Form_Decorator_Abstract
 */
require 'Epic/Form/Decorator/Abstract.php';

class Epic_Form_Element
{
	
	/**#@+
     * Constants for the coding form 
     */
    const ENCTYPE_URLENCODED = 'application/x-www-form-urlencoded';
    const ENCTYPE_MULTIPART  = 'multipart/form-data';
    
    /**
     * Form attributes
     * @var array
     */
    protected $_attribs = array();
    
	/**
     * Form elements
     * @var array
     */
    protected $_elements = array();
    
    protected $_markupElementStart = '<div>';
    protected $_markupElementEnd = '</div>';
    
    /**
     * Form error
     * @var array
     */
    private $_errors = array();
    
    /**
     * Contructor
     *
     * Set data attribute for form
     *
     * @param  array $data
     * @return void
     */
    public function __construct(array $data = array())
    {
    	$this->setData($data);
    }
    
    /**
     * Set form attribute
     *
     * @param  string $key attribute name
     * @param  mixed $value attribute value
     * @return Epic_Form_Element
     */
    public function setAttrib($key, $value)
    {
        $this->_attribs[$key] = $value;
        return $this;
    }
    
    /**
     * Retrive form attribute
     *
     * @param  string $key attribute name
     * @return string attribute value
     */
    public function getAttrib($key)
    {
        if (!isset($this->_attribs[$key])) {
            return null;
        }
        return $this->_attribs[$key];
    }
    
    /**
     * Set form data attribute
     *
     * @param  string $data
     * @return Epic_Form_Element
     */
    public function setData($data)
    {
    	if(is_array($data))
    		$this->_attribs = $data;
    	return $this;
    }
    
    /**
     * Set form id
     *
     * @param  string $id value for id attribute
     * @return Epic_Form_Element
     */
    public function setId($value)
    {
		return $this->setAttrib('id', (string)$value);
    }
    
    /**
     * Set form method
     *
     * @param  string $method value for method attribute
     * @return Epic_Form_Element
     */
    public function setMethod($method)
    {
		return $this->setAttrib('method', (string)$method);
    }
    
    /**
     * Set form action
     *
     * @param  string $action value for action attribute
     * @return Epic_Form_Element
     */
    public function setAction($action)
    {
        return $this->setAttrib('action', (string)$action);
    }
    
    /**
     * Set form enctype type
     *
     * @param  string $value value for enctype attribute
     * @return Epic_Form_Element
     */
    public function setEnctype($value)
    {
        $this->setAttrib('enctype', $value);
        return $this;
    }

    /**
     * Get form encoding type
     *
     * @return string form enctype type attribute value
     */
    public function getEnctype()
    {
        if (null === ($enctype = $this->getAttrib('enctype'))) {
            $enctype = self::ENCTYPE_URLENCODED;
            $this->setAttrib('enctype', $enctype);
        }
        return $this->getAttrib('enctype');
    }
    
    /**
     * Set markup Element Start
     *
     * @param  string $markupElementEnd
     * @return Epic_Form_Element
     */
    public function setMarkupElementStart($markupElementStart)
    {
    	$this->_markupElementStart = $markupElementStart;
    	return $this;
    }
    
    /**
     * Retrive markup Element Start
     *
     * @return string
     */
    public function getMarkupElementStart()
    {
    	if (null === $this->_markupElementStart) {
    		return null;
    	}
    	return $this->_markupElementStart;
    }
    
    /**
     * Set markup Element End
     *
     * @param  string $markupElementEnd
     * @return Epic_Form_Element
     */
    public function setMarkupElementEnd($markupElementEnd)
    {
    	$this->_markupElementEnd = $markupElementEnd;
    	return $this;
    }
    
    /**
     * Retrive markup Element End
     *
     * @return string
     */
    public function getMarkupElementEnd()
    {
    	if (null === $this->_markupElementEnd) {
    		return null;
    	}
    	return $this->_markupElementEnd;
    }
    
    /**
     * Retrive value for the elements
     *
     * @param  string $name
     * @return string|null
     */
    public function getValue($name)
    {
    	if ($element = $this->getElement($name)) {
    		return $element->getValue();
    	}
    	return null;
    }
    
    
    /**
     * Get validation errors as an array
     *
     * @return array
     */
    public function getErrors()
    {
    	return $this->_errors;
    }
    
    /**
     * Get validation errors as a string
     *
     * @return string
     */
    public function getErrorString()
    {
    	$errors = $this->getErrors();
    	return !empty($errors) ? implode('', $errors) : '';
    }
 
    /**
     * Add a html element
     * 
     * @param Epic_Form_Element_Interface $element
     * @return Epic_Form_Element
     */
    public function addElement(Epic_Form_Element_Interface $element)
    {
        $this->_elements[$element->getAttrib('name')] = $element;
        return $this;
    }
    
    /**
     * Retrive a html element
     *
     * @param  string $name
     * @return Epic_Form_Element_Abstract|null
     */
    public function getElement($name)
    {
    	if (array_key_exists($name, $this->_elements)) {
    		return $this->_elements[$name];
    	}
    	return null;
    }
    
    /**
     * Retrive all html elements
     *
     * @return array
     */
    public function getElements()
    {
    	return $this->_elements;
    }
   
    /**
     * A html elements
     * 
     * @param Epic_Form_Element_Interface $elements
     * @return Epic_Form_Element
     */
    public function addElements(array $elements)
    {
        if ($elements) {
            foreach ($elements as $element) {
                $this->addElement($element);
            }
        }
        return $this;
    }
    
    /**
     * Remove a html element
     */
    public function removeElement(Epic_Form_Element_Interface $element)
    {
    	if (in_array($element, $this->_elements, true)) {
    		$elements = array();
    		foreach ($this->_elements as $_element) {
    			if ($element !== $_element)
    				$elements[$_element->getAttrib('name')] = $_element;
    		}
    		$this->_elements = $elements;
    	}
    }
    
    /**
     * Setting values ​​from form for the elements
     *
     * @param  array $data form data
     * @return Epic_Form_Element
     */
    public function populate(array $data)
    {
    	foreach ($this->getElements() as $element) {
    		$element->setValue($data[$element->getAttrib('name')]);
    	}
    	return $this;
    }
    
    /**
     * Form valid
     *
     * @param  array $data form data
     * @return boolean
     */
    public function isValid($data)
    {
    	$valid = true;
    	// Set data for form element
    	$this->populate($data);
    	foreach ($this->getElements() as $element) {
    		if (!is_null($element->getValidator())) {
    			// Set value element to validator
    			foreach ($element->getValidator()->getValidators() as $validator) {
    				$validator->setValue($element->getValue());
    			}
    			// validate
    			if (!$element->getValidator()->isValid()) {
    				$this->_errors[] = $element->getValidator()->getErrorString();
    				$valid = false;
    			}
    		}
    	}
    	return $valid;
    }
    
    /**
     * Returns all the form elements to render
     *
     * @return string
     */
    public function __toString()
    {
    	$output = '<form id="' . $this->getAttrib('id') . '"
    				     method="' . $this->getAttrib('method') . '" 
    				     action="' . $this->getAttrib('action') . '"
    					 enctype="' . $this->getEnctype() . '"><fieldset>';
    	foreach ($this->_elements as $_element) {
    		$output .=  $this->getMarkupElementStart() . $_element->render() . $this->getMarkupElementEnd();
    	}
    	$output .= '</fieldset></form>';
    	return $output;
    }
}